open Gen
open Arbreintermediaire

let rec iafficherLabel(lb) =
    Gen.label_name(lb)

and iafficherRegistre(registre) =
  match registre with
    | Registre r ->
      "$"^(string_of_int r)
    | RegNom nom ->
      "$"^nom

and iafficherRegistreListe(registres) =
  match registres with
    | [] -> ""
    | registre::[] -> iafficherRegistre(registre)
    | registre::reste -> iafficherRegistre(registre)^iafficherRegistreListe(reste)

and iafficherFrame(frame) =
  (frame.name^"={"^
    "entry: "^iafficherLabel(frame.lentry)^
    " , return: "^iafficherLabel(frame.lreturn)^
    " , args: ["^iafficherRegistreListe(frame.args)^"]"^
    " , result: "^iafficherRegistre(frame.result)^
    " , stack: "^(string_of_int frame.stack)^
  "}")

and iafficherOperateur(operateur) = 
  match operateur with
  | IPlus -> "+"
  | IMoins ->"-"
  | IMult -> "*"
  | IDiv -> "/"


and iafficherComparateur(comparateur) = 
  match comparateur with
  | IInf -> "<"
  | ISup -> ">"
  | IInfEgal -> "<="
  | ISupEgal -> ">="
  | ICompEgal -> "=="
  | IDiff -> "<>"


and iafficherBoolean(boolean) =
  match boolean with
  | ITrue -> 
    "true"
  | IFalse -> 
    "false"
  | ICmp (e1,comp,e2) -> 
    "("^iafficherExpression(e1)^" "^iafficherComparateur(comp)^" "^iafficherExpression(e2)^")"
  | INotBoolean (boolean) -> 
    "!("^iafficherBoolean(boolean)^")"
  | IOr (b1,b2) -> 
    "("^iafficherBoolean(b1)^" || "^iafficherBoolean(b2)^")"
  | IAnd (b1,b2) -> 
    "("^iafficherBoolean(b1)^" && "^iafficherBoolean(b2)^")"


and iafficherArgumentsListe(expressions) =
  match expressions with
  | [] -> ""
  | exp::[] -> iafficherExpression(exp)
  | exp::reste -> iafficherExpression(exp)^","^iafficherArgumentsListe(reste)


and iafficherFunCall(funcall) =
	match funcall with
  | IFunCall(nom_fonction,args) ->
      "call "^nom_fonction^"("^iafficherArgumentsListe(args)^")"


and iafficherEgal(egal) =
  match egal with
	| IRegCons (reg,const) ->
    iafficherRegistre(reg)^" := "^(string_of_int const)
	| IRegFunc (reg,func) ->
    iafficherRegistre(reg)^" := "^iafficherFunCall(func)
	| IRegExpr (reg,exp) ->
    iafficherRegistre(reg)^" := "^iafficherExpression(exp)


and iafficherBlock (block) = 
  match block with
    IBlock(lb,statement) ->
      "\n"^iafficherLabel(lb)^":\n"^iafficherStatement(statement)


and iafficherExpression (expression) =
	match expression with
  | IConstante (const) ->
      string_of_int(const)
	| IUnop (expr) ->
      "-("^iafficherExpression(expr)^")"
	| IBinop (e1,op,e2) ->
	    "("^iafficherExpression(e1)^iafficherOperateur(op)^iafficherExpression(e2)^")"
  | IRegister (reg) ->
      iafficherRegistre(reg)
	| IComparator (e1,comp,e2) ->
      "("^iafficherExpression(e1)^iafficherComparateur(comp)^iafficherExpression(e2)^")"


and iafficherStatementsListe(liste) =
  match liste with
  | [] -> ""
  | s::[] -> iafficherStatement(s)
  | s::r -> iafficherStatement(s)^iafficherStatementsListe(r)


and iafficherStatement (statement) = 
  match statement with
	| IJumpIf (leif) ->
    iafficherIf(leif)^"\n"
  | IJumpWhile (lewhile) ->
    iafficherWhile(lewhile)^"\n"
	| IEgal (egal) ->
    iafficherEgal(egal)^"\n"
	| IGoto (lb) ->
    "goto "^iafficherLabel(lb)^"\n"
	| INop ->
    "nop"^"\n"
	| IFunc (fc) ->
    iafficherFunCall(fc)^"\n"
 	| IStatements (st_list) ->
    iafficherStatementsListe(st_list)
	| IBlockStatement (block) ->
    iafficherBlock(block)

and iafficherIf(leif) = 
  "jump "^iafficherBoolean(leif.testIf)^" "^iafficherLabel(leif.labelThen)^" "^iafficherLabel(leif.labelElse)^"\n"^
  iafficherBlock(leif.blockThen)^"\n"^
  iafficherBlock(leif.blockElse)^"\n"^
  iafficherLabel(leif.labelEndif)^":\nnop"


and iafficherWhile(lewhile) = 
  iafficherLabel(lewhile.labelTest)^" :\n"^
  "jump "^iafficherBoolean(lewhile.testWhile)^" "^iafficherLabel(lewhile.labelLoop)^" "^iafficherLabel(lewhile.labelEnd)^"\n"^
  iafficherBlock(lewhile.blockLoop)^"\n"^
  iafficherLabel(lewhile.labelEnd)^":"


and iafficherFrameBlock(fr) =
	match fr with
    BlockFrame (f,b) ->
      iafficherFrame(f)^"\n"^iafficherBlock(b)


and iafficherFramesBlockList(frs) =
  match frs with
    | [] -> ""
    | f::r -> "\n\n\n\n"^iafficherFrameBlock(f)^"\n"^iafficherFramesBlockList(r)

let iafficherIprogramme(prog) =
  ".text\n"^
  iafficherBlock(prog.text)^
  iafficherFramesBlockList(prog.frames)

let iafficher(prog) = 
  let oo = open_out "intermediaire.txt" in
    let string_prog = iafficherIprogramme(prog) in
    begin
      output_string oo string_prog;
      close_out oo
    end